import { IPoint } from "@/models/gui";
import { average, gauss, IFn } from "@/models/math";
import { getRidgeRegressionFittingFn } from "./ridge-regression";

// 高斯函数插值 手动求解
export function getGaussInterpolationFn (points: IPoint[]): IFn {
  const n = points.length;
  const B: number[][] = [];
  const C: number[] = points.map(() => null);
  const _b = average(points.map(p => p.y));
  const Y = points.map(p => p.y - _b);
  const X = points.map(p => p.x);
  const o = average(X);
  for (let i = 0; i < n; i++) {
    B[i] = [];
    for (let j = 0; j < n; j++) {
      B[i][j] = gauss((X[i] - X[j]), o);
    }
    // console.log([...B[i]]);
  }
  for (let k = 0; k < n - 1; k++) {
    const bk = B[k];
    for (let i = k + 1; i < n; i++) {
      const bi = B[i];
      const b = bi[k];
      for (let j = k; j < n; j++) {
        bi[j] = bi[j] / b - bk[j] / bk[k];
      }
      Y[i] = Y[i] / b - Y[k] / bk[k];
    }
  }
  C[n - 1] = Y[n-1] / B[n-1][n-1];
  for (let k = n - 1; k >= 0; k--) {
    const bk = B[k];
    let sum = 0;
    for (let j = k + 1; j < n; j++) {
      sum += bk[j] * C[j];
    }
    C[k] = (Y[k] - sum) / bk[k];
  }
  return (x) => {
    let y = 0;
    let xn = 1;
    C.forEach(c => {
      y += c * xn;
      xn = xn * x;
    });
    return y;
  };
}

// 拟合 岭回归
export function getGaussCurveFittingFn (points: IPoint[]): IFn {
  const cores: IFn[] = [];
  const o = average(points.map(p => p.x));

  for (let i = 0; i < points.length - 1; i++) {
    cores[i] = (x) => gauss(x - points[i].x, o);
  }
  return getRidgeRegressionFittingFn(cores, points, 1 / points.length);
}